home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 00 - Game Programming Primer / HelloWorld3.c < prev    next >
Text File  |  1995-06-29  |  21KB  |  457 lines

  1. //==============================================================================================\\
  2. //        -----------------------------------------------------------------------------------        \\
  3. //        HelloWorld3.c version 1.0.0    copyright © 1993…1995 Jamie McCornack, john calhoun            \\
  4. //        -----------------------------------------------------------------------------------        \\
  5. //         Demo program for Macintosh GameWriter 1.0.0, a training program…                        \\
  6. //        …for beginning Mac game programmers. MGW1 includes MGWExterns1.h, MGWUtilities1.c,…        \\
  7. //        …MGWSound1.c, MGWGraphics1.c, MGWGraphicsBWLite1.c, HelloWorld.rsrc and an assortment…    \\
  8. //        …of demo programs; projects HelloWorld1.π etc. and source code files HelloWorld1.c etc.    \\
  9. //         A tutorial is available in Tricks of the Mac Game Programming Gurus, published…        \\
  10. //        …by Hayden Books, August 1995.                                                            \\
  11. //                                                                                                \\
  12. //        This code is offered by the copyright holders for no fee and for whatever use…            \\
  13. //        …you care to make of it, but we do hope you remember where it came from.                \\
  14. //                                                                                                \\
  15. //        Please send bug reports to MacGameDev at America OnLine.    macgamedev@aol.com            \\
  16. //        Suggestions and observations are also appreciated.                                        \\
  17. //        Updates and upgrades will be available now and then from the above e-mail address.        \\
  18. //==============================================================================================\\
  19.  
  20. // This program opens a window, displays an 8-bit color background, and at first…
  21. // …mouseclick, runs two clams across the screen. At second mouseclick, Clamity Jane stops,…
  22. // …talks, and flaps her face for 40 frames as Clem the Clam runs by.
  23.  
  24.  
  25. #include "MGWExterns1.h"
  26.  
  27. #define     kPutInFront    (WindowPtr)-1L
  28. #define     kWaitTicks     4L    // Sets the delay in Ticks between frames. Try 3. Try 2. Try 0.
  29. #define     kJaneStepLength    12    // Sets the distance in pixels between Clamity Jane's moves.
  30. #define     kClemStepLength    16    // Sets the distance in pixels between Clem the Clam's moves.
  31. #define  kFrontFace        0
  32. #define  kBlinkFace     1
  33. #define  kEehFace        2
  34. #define  kOohFace        3
  35. #define  kStepRightFace    4
  36. #define  kWalkRightFace    5
  37. #define  kRunRightFace    6
  38. #define  kMaxFaces        7
  39.                 // The resource constants--with 'r' prefix like Apple wants them.
  40. #define  rJaneFacesID    136        // The 'PICT' ID# where the views of Jane are located.
  41. #define  rClemFacesID    135        // The 'PICT' ID# where the views of Clem are located.
  42. #define  rMasksID        130        // The 'PICT' ID# where the clam masks are located.
  43. #define  rBackgroundID    134        // The 'PICT' ID# where the background picture is located.
  44. #define  rMainWindowID    128        // The 'WIND' resource ID# for the main window.
  45.  
  46. #define  rHelloSndID    3000
  47. #define  rFootstepSndID    3001
  48. #define  rImpactSndID    3002
  49. #define  rDizzySndID    3003
  50.  
  51. #define  kColorBitsNeeded    8
  52.     
  53. typedef struct
  54. {
  55.     Rect    face;
  56.     Rect    mask;
  57. } tSpriteType;
  58.  
  59.  
  60. Rect    bigPictureRect, masksRect,  allComboRect;
  61. Rect    janeFacesRect, janeIsAtRect, janeWasAtRect, janeComboRect;
  62. Rect    clemFacesRect, clemIsAtRect, clemWasAtRect, clemComboRect;
  63. CGrafPtr    workCPort, janeFacesCPort, clemFacesCPort, backgroundCPort;
  64. GrafPtr mainWindow, masksPort;
  65. Boolean    itWorked, contactFlag;
  66. long    targetTick;
  67. short    janeSprite, clemSprite, thisFaceCounter;
  68.  
  69. tSpriteType    sprite[kMaxFaces];
  70.  
  71. extern    Boolean        gUserWantsSound;
  72.     
  73.     
  74. //==============================================================  Prototypes
  75.  
  76. void InitAll(void);
  77. void OpenMainWindow (void);
  78. void SetTheRects(void);
  79. void SetTheCPorts(void);
  80. void CopyBothAtOnce (void);
  81. void CopyOneAtATime (void);
  82. void ShowClams (void);
  83. void DoDelay (void);
  84. void JaneLoop (void);
  85. void ClemLoop (void);
  86. void JaneSpeaks (void);
  87.  
  88. //==============================================================  Functions
  89.  
  90. //--------------------------------------------------------------  InitAll
  91.  
  92. void InitAll(void)
  93. {
  94.     InitToolbox();
  95.     if (WhatsOurDepth() != kColorBitsNeeded)    // Compare color depth with what…
  96.         RedAlert(kErrNot8BitColor);                // …we want. If not equal, exit.
  97.     gUserWantsSound = TRUE;
  98.     InitializeForSound();
  99.     SetTheRects();        // Since some of these Rects define fields in CGrafPorts,…
  100.     SetTheCPorts();        // …set the rects before setting the ports.
  101.     janeSprite = kStepRightFace;
  102.     clemSprite = kRunRightFace;
  103.     thisFaceCounter = 0;
  104.     contactFlag = FALSE;
  105.     targetTick = TickCount() + kWaitTicks;
  106.     HideCursor();        // This demo doesn't use mouse input, so why look at it?
  107. }
  108.  
  109. //--------------------------------------------------------------  OpenMainWindow
  110.  
  111. void OpenMainWindow (void)
  112. {
  113.     mainWindow = GetNewCWindow(128, 0L, kPutInFront);    // Load window from resource.
  114.     ShowWindow((GrafPtr)mainWindow);                    // Now display it.
  115.     SetPort((GrafPtr)mainWindow);                        // Make its port current.
  116.     ClipRect(&bigPictureRect);                            // Set its clip region.
  117.     CopyRgn(mainWindow->clipRgn, mainWindow->visRgn);    // Set its visRgn.
  118.     ForeColor(blackColor);                                // Set its pen color to black.
  119.     BackColor(whiteColor);                                // Set background color white.
  120. }
  121.  
  122. //--------------------------------------------------------------  SetTheRects
  123.  
  124. void SetTheRects(void)    // The most tedious part of programming this type of game.
  125. {
  126.     SetRect(&janeFacesRect, 0, 0, 448, 64);        // Size and shape of BitMap for the sprite faces.
  127.     SetRect(&clemFacesRect, 0, 0, 448, 64);        // Size and shape of BitMap for the sprite faces.
  128.     SetRect(&masksRect, 0, 0, 448, 32);        // Size and shape of BitMap for the sprite masks.
  129.     SetRect(&bigPictureRect, 0, 0, 512, 322);    // The shape of the picture we'll put in the main window, workCPort and backgroundCPort.}
  130.     SetRect(&janeIsAtRect, 80, 240, 112, 272);    // The shape (32 x 32) of the images of Jane, and the position of the first image.}
  131.     janeWasAtRect = janeIsAtRect;                // Initializing janeIsAtRect...it has to start somewhere, and this is handy.}
  132.     janeComboRect = janeIsAtRect;
  133.     SetRect(&clemIsAtRect, 40, 244, 72, 276);    // The shape (32 x 32) of the images of Clem, and the position of the first image.}
  134.     clemWasAtRect = clemIsAtRect;                // Initializing clemIsAtRect...it has to start somewhere, and this is handy.}
  135.     clemComboRect = clemIsAtRect;
  136.         // And now, the tedium. In this sample, all we're doing is showing the clam running across the screen to the right.}
  137.         // However, if you use ResEdit and look at 'PICT' 129 in Sample.rsrc, you'll find 28 different views of the clam.}
  138.         // If we wanted the clam to run left too, and walk slowly, and face the user, and blink its eyes, we'd be calling…}
  139.         // …SetRect 56 times--one face and one mask per sprite. And if we had jumping clams and rear views of clams…}
  140.         // …and starfish and clamdiggers and other hazards of the clam environment, we might have hundreds of rects to set.}
  141.     SetRect(&sprite[kFrontFace].face, 320, 32, 352, 64);    // The shape and position of sprite[kFrontFace].face on facesCPort.portPixMap.
  142.     SetRect(&sprite[kFrontFace].mask, 320, 0, 352, 32);    // The shape and position of sprite[kFrontFace].mask on masksPort.portPixMap.
  143.     SetRect(&sprite[kBlinkFace].face, 320, 0, 352, 32);    // Note that some faces (e.g. eyes open or closed) use the same mask,…
  144.     SetRect(&sprite[kBlinkFace].mask, 320, 0, 352, 32);    // …since they have the same silhouette.}
  145.     SetRect(&sprite[kEehFace].face, 352, 0, 384, 32);    // I could write more comments here, but setting these rects…
  146.     SetRect(&sprite[kEehFace].mask, 352, 0, 384, 32);    // …is already tedious enough without a bunch of busy-work.
  147.     SetRect(&sprite[kOohFace].face, 352, 32, 384, 64);
  148.     SetRect(&sprite[kOohFace].mask, 352, 0, 384, 32);    
  149.     SetRect(&sprite[kStepRightFace].face, 192, 0, 224, 32);    
  150.     SetRect(&sprite[kStepRightFace].mask, 192, 0, 224, 32);    
  151.     SetRect(&sprite[kWalkRightFace].face, 224, 0, 256, 32);    
  152.     SetRect(&sprite[kWalkRightFace].mask, 224, 0, 256, 32);    
  153.     SetRect(&sprite[kRunRightFace].face, 160, 0, 192, 32);    // BTW, there are plenty more clam faces and masks in the 'PICT's,…
  154.     SetRect(&sprite[kRunRightFace].mask, 160, 0, 192, 32);    // …if you feel you need rect setting practice.  :-)
  155. }
  156.  
  157. //--------------------------------------------------------------  SetTheCPorts
  158.  
  159. void SetTheCPorts(void)    // Create the CGrafPorts and load their .portPixMap fields.
  160. {
  161.             // Create BitMap for sprite masks. NOTE THIS IS A BITMAP!
  162.     CreateOffScreenBitMap (&masksRect, &masksPort);
  163.     LoadGraphic (rMasksID);        // …load 'PICT' resource for the clam masks.
  164.     
  165.             // Create PixMap for Jane faces.
  166.     CreateOffScreenPixMap (&janeFacesRect, &janeFacesCPort);
  167.     LoadGraphic (rJaneFacesID);        // …load 'PICT' resource for the clam faces.
  168.  
  169.             // Create PixMap for Clem faces.
  170.     CreateOffScreenPixMap (&clemFacesRect, &clemFacesCPort);
  171.     LoadGraphic (rClemFacesID);        // …load 'PICT' resource for the clam faces.
  172.  
  173.             // Create PixMap for the background.
  174.     CreateOffScreenPixMap (&bigPictureRect, &backgroundCPort);
  175.     LoadGraphic(rBackgroundID);    // …load 'PICT' resource for the background picture.
  176.     
  177.             // Create PixMap for offscreen graphics work.
  178.     CreateOffScreenPixMap (&bigPictureRect, &workCPort);
  179.  
  180.     OpenMainWindow();
  181.  
  182.         //{This fills the main window with the background picture, so the user can see it.
  183.     CopyBits(&((GrafPtr)backgroundCPort)->portBits,
  184.         &((GrafPtr)mainWindow)->portBits, 
  185.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  186.  
  187. // This fills the workCPort.portPixMap with the background picture, so updates can be done quickly.
  188.     CopyBits(&((GrafPtr)backgroundCPort)->portBits,
  189.         &((GrafPtr)workCPort)->portBits, 
  190.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  191. }
  192.  
  193. //--------------------------------------------------------------  CopyBothAtOnce
  194.  
  195. void CopyBothAtOnce (void)    //Display the clams on the screen when they're close together.
  196. {
  197.         //UnionRect(clemComboRect, larryComboRect, allComboRect);
  198.         //{Find the smallest rectangle which will cover Larry and Clem.}
  199.     UnionRect(&janeComboRect, &clemComboRect, &allComboRect);
  200. // Find the smallest rectangle which will cover the old position of Clem and the new.
  201.         //CopyBits(BitMapPtr(workMapC^.portPixMap^)^, GrafPtr(mainWndo)^.portBits, allComboRect, allComboRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  202.     CopyBits(&((GrafPtr)workCPort)->portBits, 
  203.         &(((GrafPtr)mainWindow)->portBits), 
  204.         &allComboRect, &allComboRect, srcCopy, mainWindow->visRgn);
  205.         //CopyBits(BitMapPtr(backgroundMapC^.portPixMap^)^, BitMapPtr(workMapC^.portPixMap^)^, allComboRect, allComboRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  206.         //{Restore the workPort by covering up our clams with the background they obscure.  This way, workPort is…}
  207.     CopyBits(&((GrafPtr)backgroundCPort)->portBits, 
  208.         &(((GrafPtr)workCPort)->portBits), 
  209.         &allComboRect, &allComboRect, srcCopy, mainWindow->visRgn);
  210. // Restore the workCPort by covering up our clam with the background it obscures.
  211. // This way, workCPort->portPixMap is identical to backgroundCPort->portPixMap,…
  212. // without having to copy the entire PixMap.
  213. }
  214.  
  215. //--------------------------------------------------------------  CopyOneAtATime
  216.  
  217. void CopyOneAtATime (void)    // Display the clams on the screen when they're far apart.
  218. {
  219.         //CopyBits(BitMapPtr(workMapC^.portPixMap^)^, GrafPtr(mainWndo)^.portBits, larryComboRect, larryComboRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  220.     CopyBits(&((GrafPtr)workCPort)->portBits, 
  221.         &(((GrafPtr)mainWindow)->portBits), 
  222.         &janeComboRect, &janeComboRect, srcCopy, mainWindow->visRgn);
  223. // Copy the contents of janeComboRect from workCPort->portPixMap to the main window. In one swell foop, old Jane…
  224. //…will be erased, and the new Jane overlayed onto the background picture. Wallah! Flicker-free animation!
  225.     //CopyBits(BitMapPtr(workMapC^.portPixMap^)^, GrafPtr(mainWndo)^.portBits, clemComboRect, clemComboRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  226.     CopyBits(&((GrafPtr)workCPort)->portBits, 
  227.         &(((GrafPtr)mainWindow)->portBits), 
  228.         &clemComboRect, &clemComboRect, srcCopy, mainWindow->visRgn);
  229. // Copy the contents of clemComboRect from workCPort->portPixMap to the main window. In one swell foop, old Clem
  230. //…will be erased, and the new Clem overlayed onto the background picture. Wallah! Flicker-free animation!
  231.     //CopyBits(BitMapPtr(backgroundMapC^.portPixMap^)^, BitMapPtr(workMapC^.portPixMap^)^, larryRect, larryRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  232.     CopyBits(&((GrafPtr)backgroundCPort)->portBits, 
  233.         &(((GrafPtr)workCPort)->portBits), 
  234.         &janeIsAtRect, &janeIsAtRect, srcCopy, mainWindow->visRgn);
  235. // Restore the workCPort by covering up Jane's image with the background it obscures.
  236. // This way, workCPort->portPixMap is identical to backgroundCPort->portPixMap,…
  237. // without having to copy the entire PixMap.
  238.     CopyBits(&((GrafPtr)backgroundCPort)->portBits, 
  239.         &(((GrafPtr)workCPort)->portBits), 
  240.         &clemIsAtRect, &clemIsAtRect, srcCopy, mainWindow->visRgn);
  241. // Restore the workCPort by covering up Clem's image with the background it obscures.
  242. // This way, workCPort->portPixMap is identical to backgroundCPort->portPixMap,…
  243. // without having to copy the entire PixMap.
  244.         //CopyBits(BitMapPtr(backgroundMapC^.portPixMap^)^, BitMapPtr(workMapC^.portPixMap^)^, clemRect, clemRect, srcCopy, GrafPtr(mainWndo)^.visRgn);
  245. }
  246.  
  247. //--------------------------------------------------------------  ShowClam 
  248.  
  249. void ShowClams (void)    // Do the animation and make it appear on the screen.
  250. {
  251.     Rect dummyRect;
  252.     
  253.     CopyMask(&((GrafPtr)janeFacesCPort)->portBits, 
  254.         &((GrafPtr)masksPort)->portBits, 
  255.         &((GrafPtr)workCPort)->portBits, 
  256.         &sprite[janeSprite].face, 
  257.         &sprite[janeSprite].mask, 
  258.         &janeIsAtRect);
  259. // Now there is an image of a clam in the new position in workMap.  If we had done this work in…
  260. // mainWindow, we would have seen considerable flickering.  Instead, we did it offscreen, and left the…
  261. // previous image of the clam visible on the screen while we worked.
  262.  
  263.     UnionRect(&janeWasAtRect, &janeIsAtRect, &janeComboRect);
  264. // Find the smallest rectangle which will cover the old position of Jane and the new.
  265.  
  266. CopyMask(&((GrafPtr)clemFacesCPort)->portBits, 
  267.         &((GrafPtr)masksPort)->portBits, 
  268.         &((GrafPtr)workCPort)->portBits, 
  269.         &sprite[clemSprite].face, 
  270.         &sprite[clemSprite].mask, 
  271.         &clemIsAtRect);
  272. // Now there is an image of a clam in the new position in workMap.  If we had done this work in…
  273. // mainWindow, we would have seen considerable flickering.  Instead, we did it offscreen, and left the…
  274. // previous image of the clam visible on the screen while we worked.
  275.  
  276.     UnionRect(&clemWasAtRect, &clemIsAtRect, &clemComboRect);
  277. // Find the smallest rectangle which will cover the old position of Clem and the new.
  278.  
  279.  
  280.     if (SectRect(&clemIsAtRect, &janeIsAtRect, &dummyRect))
  281.     {
  282.         contactFlag = TRUE;
  283.         CopyBothAtOnce();
  284.     }
  285.     else
  286.     {
  287.         contactFlag = FALSE;
  288.         CopyOneAtATime();
  289.     }
  290. }
  291. //    CopyBits(&((GrafPtr)workCPort)->portBits, 
  292.         //&(((GrafPtr)mainWindow)->portBits), 
  293.         //&clamComboRect, &clamComboRect, srcCopy, mainWindow->visRgn);
  294. // Copy the contents of comboRect from workCPort->portPixMap to the main window. In one swell foop, the old clam…}
  295. //…will be erased, and the new clam overlayed onto the background picture. Wallah! Flicker-free animation!}
  296.  
  297.     //CopyBits(&((GrafPtr)backgroundCPort)->portBits, 
  298.         //&(((GrafPtr)workCPort)->portBits), 
  299.         //&clamIsAtRect, &clamIsAtRect, srcCopy, mainWindow->visRgn);
  300. // Restore the workCPort by covering up our clam with the background it obscures.
  301. // This way, workCPort->portPixMap is identical to backgroundCPort->portPixMap,…
  302. // without having to copy the entire PixMap.
  303. //}
  304.  
  305. //--------------------------------------------------------------  DoDelay
  306.  
  307. // This is the companion function to the above function (LogNextTick()).
  308. // We do nothing but loop until TickCount() catches up with (or passes) our…
  309. // global variable tickNext.
  310.  
  311. void DoDelay (void)
  312. {
  313.     do
  314.     {
  315.     }
  316.     while (TickCount() < targetTick);            // Loop until TickCount() catches up.
  317.     targetTick = TickCount() + kWaitTicks;
  318. }
  319.  
  320. //--------------------------------------------------------------  JaneLoop
  321.  
  322. void JaneLoop (void)
  323. {
  324.     switch    (janeSprite)                    //If the current view of jane is…
  325.     {    case    (kStepRightFace):             // …kStepRightFace, then set thisSprite to…
  326.         {    janeSprite = kWalkRightFace;    // …kWalkRightFace, and if it is currently…
  327.             break;    }
  328.         case    (kWalkRightFace):             // …kWalkFace, then set it to…
  329.         {    janeSprite = kRunRightFace;        // …kRunRightFace.
  330.             break;    }
  331.     // And if it was neither kStepRightFace nor kWalkRightFace, then janeSprite was either…
  332.         default                    :             // …kRunRightFace, or what it was when RunRight()…
  333.             janeSprite = kStepRightFace;    // …was called, so we set it to kStepRightFace
  334.     }
  335.     
  336.     janeWasAtRect = janeIsAtRect;            // Store the clam's current position as its last position,…
  337.                                             // …we'll be erasing it next time through the loop.
  338.     OffsetRect(&janeIsAtRect, kJaneStepLength, 0);    // Set the clam's next position--it'll be…
  339.                                             // …kStepLength pixels to the right of its last position.
  340.     if (janeIsAtRect.left > 512)                // If the clam has wandered out of sight,…
  341.     {                                        // …set the right border of clamIsAtRect…
  342.         janeIsAtRect.right = 0;                // …to the left edge of the screen…
  343.         janeIsAtRect.left = -32;            // …and move the left border of clamIsAtRect…
  344.     }                                        // …as needed to maintain its 32 x 32 shape & size.
  345. }
  346.  
  347. //--------------------------------------------------------------  ClemLoop
  348.  
  349. void ClemLoop (void)
  350. {
  351.     switch    (clemSprite)                    //If the current view of Clem is…
  352.     {    case    (kStepRightFace):             // …kStepRightFace, then set thisSprite to…
  353.         {    clemSprite = kWalkRightFace;    // …kWalkRightFace, and if it is currently…
  354.             break;    }
  355.         case    (kWalkRightFace):             // …kWalkFace, then set it to…
  356.         {    clemSprite = kRunRightFace;        // …kRunRightFace.
  357.             break;    }
  358.     // And if it was neither kStepRightFace nor kWalkRightFace, then clemSprite was either…
  359.         default                    :             // …kRunRightFace, or what it was when RunRight()…
  360.             clemSprite = kStepRightFace;    // …was called, so we set it to kStepRightFace
  361.     }
  362.     clemWasAtRect = clemIsAtRect;            // Store the clam's current position as its last position,…
  363.                                             // …we'll be erasing it next time through the loop.
  364.     OffsetRect(&clemIsAtRect, kClemStepLength, 0);    // Set the clam's next position--it'll be…
  365.                                             // …kStepLength pixels to the right of its last position.
  366.     if (clemIsAtRect.left > 512)                // If the clam has wandered out of sight,…
  367.     {                                        // …set the right border of clamIsAtRect…
  368.         clemIsAtRect.right = 0;                // …to the left edge of the screen…
  369.         clemIsAtRect.left = -32;            // …and move the left border of clamIsAtRect…
  370.     }                                        // …as needed to maintain its 32 x 32 shape & size.
  371.     if (clemSprite == kStepRightFace)                // Only sound a footstep in pose where foot strikes ground.
  372.           PlayASound(rFootstepSndID, kLowSoundPriority);        //Ahh, the pitter patter of tiny feet.
  373. }
  374.  
  375. //--------------------------------------------------------------  JaneSpeaks
  376.  
  377. // This routine has the clam stop moving, face the screen, and move its face.
  378.  
  379. void JaneSpeaks (void)
  380. {
  381.     while (thisFaceCounter < 40)
  382.     {
  383.         thisFaceCounter = thisFaceCounter + 1;
  384.          switch (thisFaceCounter)
  385.          {    case    (1): 
  386.             {    janeSprite = kFrontFace;
  387.                 break;    }
  388.             case    (2): 
  389.             {    janeSprite = kEehFace;
  390.                 break;    }
  391.             case    (4): 
  392.             {    janeSprite = kFrontFace;
  393.                 break;    }
  394.             case    (5): 
  395.             {    janeSprite = kOohFace;
  396.                 break;    }
  397.             case    (9): 
  398.             {    janeSprite = kEehFace;
  399.                 break;    }
  400.             case    (11): 
  401.             {    janeSprite = kOohFace;
  402.                 break;    }
  403.             case    (13): 
  404.             {    janeSprite = kFrontFace;
  405.                 break;    }
  406.             case    (16): 
  407.             {    janeSprite = kBlinkFace;
  408.                 break;    }
  409.             case    (18): 
  410.             {    janeSprite = kFrontFace;
  411.                 break;    }
  412.             case    (35): 
  413.             {    janeSprite = kBlinkFace;
  414.                 break;    }
  415.             case    (38): 
  416.             {    janeSprite = kFrontFace;
  417.                 break;    }
  418.         }
  419.         ClemLoop();
  420.         ShowClams();
  421.         DoDelay();        // Do nothing for a while, so the lips don't flap too fast.
  422.     }
  423. }
  424.  
  425. //--------------------------------------------------------------  main
  426. //----------------------------------------------------------------------
  427.  
  428. void main(void)
  429. {
  430.     InitAll();
  431.     while (!Button())    // Before the user presses the mouse button, nothing happens.
  432.         {
  433.         }
  434.     while (Button())    // When the user presses the mouse button, nothing happens.
  435.         {
  436.         }
  437.     while (!Button())    // When the mouse button is released, continue to…
  438.         {
  439.         JaneLoop();        // Put Jane in her next position.
  440.         ClemLoop();        // Put Clem in his next position.
  441.         ShowClams();    // Put the clams on the screen.
  442.         DoDelay();        // Keep everything from happening too fast.
  443.         }
  444.     while (Button())    // …until the button is pushed.
  445.         {                // Do nothing until the button is released.
  446.         }
  447.     PlayASound(rHelloSndID, kMediumSoundPriority);
  448.     JaneSpeaks();            // Includes ClemLoop(), ShowClams(), and DoDelay().
  449.     CloseDownSound();
  450.     InitCursor();        // Rarely needed, since most programs call InitCursor on startup. Still, it's…
  451.                     // a good habit to leave everything in normal condition when your programs quit.
  452. }                        // And we're done.
  453.  
  454. //------------------------------------------------------------------------------------------\\
  455. //                                    End HelloWorld3.c                                        \\
  456. //------------------------------------------------------------------------------------------\\
  457.